package net.zdsoft.wpchat.support.service.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;

import net.zdsoft.keel.util.UUIDGenerator;
import net.zdsoft.keel.util.Validators;
import net.zdsoft.wpchat.support.dao.AuthGroupDao;
import net.zdsoft.wpchat.support.dao.GroupPermDao;
import net.zdsoft.wpchat.support.dao.OperatorDao;
import net.zdsoft.wpchat.support.dao.OperatorGroupDao;
import net.zdsoft.wpchat.support.dto.OperatorDto;
import net.zdsoft.wpchat.support.entity.AuthCatalog;
import net.zdsoft.wpchat.support.entity.AuthConfig;
import net.zdsoft.wpchat.support.entity.AuthGroup;
import net.zdsoft.wpchat.support.entity.AuthGroupUser;
import net.zdsoft.wpchat.support.entity.AuthModule;
import net.zdsoft.wpchat.support.entity.AuthOperation;
import net.zdsoft.wpchat.support.entity.GroupPermission;
import net.zdsoft.wpchat.support.entity.Operator;
import net.zdsoft.wpchat.support.entity.OperatorGroup;
import net.zdsoft.wpchat.support.entity.UserConfig;
import net.zdsoft.wpchat.support.enums.AuthGroupTypeEnum;
import net.zdsoft.wpchat.support.enums.OperatorStateEnum;
import net.zdsoft.wpchat.support.service.AuthCacheService;
import net.zdsoft.wpchat.support.service.AuthService;

/**
 * 权限Service
 * 
 * @author xuan
 * @version $Revision: 1.0 $, $Date: 2014-9-22 下午10:44:24 $
 */
@Service
public class AuthServiceImpl implements AuthService {

    @Resource
    private OperatorGroupDao operatorGroupDao;
    @Resource
    private OperatorDao operatorDao;
    @Resource
    private AuthGroupDao authGroupDao;
    @Resource
    private GroupPermDao groupPermDao;
    @Resource
    private AuthCacheService authCacheService;

    @Override
    public UserConfig getUserConfig(String operatorId) {
        List<OperatorGroup> opGroupList = operatorGroupDao.findByOperatorId(operatorId);
        UserConfig userConfig = null;
        if (opGroupList.size() > 0) {
            List<String> groupIdList = new ArrayList<String>();
            for (OperatorGroup og : opGroupList) {
                groupIdList.add(og.getGroupId());
            }
            userConfig = authCacheService.getUserConfigByGroupIds(groupIdList.toArray(new String[0]));
        }
        return userConfig;
    }

    @Override
    public List<Operator> getOperatorsByGroupIds(String operatorId, String... groupIds) {
        boolean isSystemGroupUser = isSystemGroupUser(operatorId);

        List<Operator> resultList = new ArrayList<Operator>();

        if (Validators.isEmpty(groupIds) || Validators.isEmpty(groupIds[0])) {
            if (isSystemGroupUser) {
                resultList = operatorDao.findAll();
            }
            else {
                List<AuthGroup> customGroupList = authGroupDao.findByType(AuthGroupTypeEnum.CUSTOM);
                Set<String> customGroupIdSet = new HashSet<String>();
                for (AuthGroup group : customGroupList) {
                    customGroupIdSet.add(group.getId());
                }
                List<OperatorGroup> customOperatorGroupList = operatorGroupDao.findByGroupIds(customGroupIdSet
                        .toArray(new String[0]));
                Set<String> customOperatorIdSet = new HashSet<String>();
                for (OperatorGroup og : customOperatorGroupList) {
                    customOperatorIdSet.add(og.getOperatorId());
                }
                resultList = operatorDao.findByIds(customOperatorIdSet.toArray(new String[0]));
            }
        }
        else {
            if (isSystemGroupUser) {
                List<OperatorGroup> operGroupList = operatorGroupDao.findByGroupIds(groupIds);
                Set<String> operatorIdSet = new HashSet<String>();
                for (OperatorGroup og : operGroupList) {
                    operatorIdSet.add(og.getOperatorId());
                }
                resultList = operatorDao.findByIds(operatorIdSet.toArray(new String[0]));
            }
            else {
                if (!isSystemGroupUser) {
                    List<OperatorGroup> operGroupList = operatorGroupDao.findByGroupIds(groupIds);
                    Set<String> operatorIdSet = new HashSet<String>();
                    for (OperatorGroup og : operGroupList) {
                        operatorIdSet.add(og.getOperatorId());
                    }
                    resultList = operatorDao.findByIds(operatorIdSet.toArray(new String[0]));
                }
                List<AuthGroup> customGroupList = authGroupDao.findByIds(groupIds);
                boolean groupValid = true;
                for (AuthGroup group : customGroupList) {
                    if (!AuthGroupTypeEnum.CUSTOM.equals(group.getType())) {
                        groupValid = false;
                        break;
                    }
                }

                if (!groupValid) {
                    resultList = Collections.emptyList();
                }
                else {
                    List<OperatorGroup> operGroupList = operatorGroupDao.findByGroupIds(groupIds);
                    Set<String> operatorIdSet = new HashSet<String>();
                    for (OperatorGroup og : operGroupList) {
                        operatorIdSet.add(og.getOperatorId());
                    }
                    resultList = operatorDao.findByIds(operatorIdSet.toArray(new String[0]));
                }
            }
        }
        return resultList;
    }

    @Override
    public List<AuthGroup> getAllGroup(String operatorId) {
        List<AuthGroup> resultList = new ArrayList<AuthGroup>();
        if (isSystemGroupUser(operatorId)) {
            resultList = authGroupDao.findAll();
        }
        else {
            resultList = authGroupDao.findByType(AuthGroupTypeEnum.CUSTOM);
        }
        return resultList;
    }

    @Override
    public List<GroupPermission> getGroupPerms(String... groupIds) {
        return groupPermDao.findByGroupIds(groupIds);
    }

    @Override
    public Map<String, GroupPermission> getOperationId2GroupPermMap(String groupId) {
        if (Validators.isEmpty(groupId)) {
            return Collections.emptyMap();
        }
        Map<String, GroupPermission> resultMap = new HashMap<String, GroupPermission>();
        List<GroupPermission> groupPermList = getGroupPerms(groupId);
        for (GroupPermission gp : groupPermList) {
            resultMap.put(gp.getAuthOperationId(), gp);
        }
        return resultMap;
    }

    @Override
    public void addGroup(AuthGroup authGroup) {
        authGroup.setType(AuthGroupTypeEnum.CUSTOM.getValue());
        authGroupDao.insertGroup(authGroup);
    }

    @Override
    public void removeGroup(String... groupIds) {
        // List<OperatorGroup> ogList =
        // operatorGroupDao.findByGroupIds(groupIds);
        // Set<String> operatorIdSet = new HashSet<String>();
        // for (OperatorGroup og : ogList) {
        // operatorIdSet.add(og.getOperatorId());
        // }
        groupPermDao.deleteByGroupIds(groupIds);
        operatorGroupDao.deleteByGroupIds(groupIds);
        // operatorDao.deleteOperator(operatorIdSet.toArray(new String[0]));
        authGroupDao.deleteGroup(groupIds);
    }

    @Override
    public void modifyGroup(AuthGroup authGroup) {
        if (Validators.isEmpty(authGroup.getId())) {
            return;
        }
        authGroup.setModifiedTime(new Date());
        authGroupDao.updateGroup(authGroup);
    }

    @Override
    public void addOperator(OperatorDto dto) {
        if (operatorDao.findByLoginName(dto.getLoginName()) != null) {
            return;
        }

        Operator operator = new Operator();
        UUIDGenerator uuid = new UUIDGenerator();
        String operId = uuid.generateHex();
        operator.setId(operId);
        operator.setLoginName(dto.getLoginName());
        operator.setName(dto.getName());
        operator.setType(dto.getType());
        operator.setRegionRule(dto.getRegionRule());
        operator.setState(OperatorStateEnum.STATE_ACTIVE.getValue());
        operator.setPassword(dto.getLoginName());
        operator.setCreationTime(dto.getCreationTime());

        List<OperatorGroup> groupList = new ArrayList<OperatorGroup>();
        for (String groupId : dto.getGroupIds()) {
            OperatorGroup group = new OperatorGroup();
            group.setGroupId(groupId);
            group.setOperatorId(operId);
            group.setCreationTime(new Date());
            groupList.add(group);
        }

        operatorDao.insertOperator(operator);
        operatorGroupDao.insertGroups(groupList.toArray(new OperatorGroup[0]));
    }

    @Override
    public void modifyOperator(OperatorDto dto) {
        Operator oper = operatorDao.findByLoginName(dto.getLoginName());
        if (oper != null && !oper.getId().equals(dto.getId())) {
            return;
        }

        Operator operator = new Operator();
        operator.setId(dto.getId());
        operator.setLoginName(dto.getLoginName());
        operator.setName(dto.getName());
        operator.setType(dto.getType());
        operator.setRegionRule(dto.getRegionRule());
        List<OperatorGroup> groupList = new ArrayList<OperatorGroup>();
        for (String groupId : dto.getGroupIds()) {
            OperatorGroup group = new OperatorGroup();
            group.setGroupId(groupId);
            group.setOperatorId(dto.getId());
            groupList.add(group);
        }
        operatorGroupDao.deleteByOperatorIds(dto.getId());
        operatorDao.modifyOperator(operator);
        operatorGroupDao.insertGroups(groupList.toArray(new OperatorGroup[0]));
    }

    @Override
    public void removeOperator(String operatorId) {
        operatorDao.deleteOperator(operatorId);
        operatorGroupDao.deleteByOperatorIds(operatorId);
    }

    @Override
    public OperatorDto getOperatorById(String operatorId) {
        List<Operator> operatorList = operatorDao.findByIds(operatorId);
        OperatorDto dto = null;
        if (!operatorList.isEmpty()) {
            dto = new OperatorDto();
            Operator operator = operatorList.get(0);
            dto.setId(operator.getId());
            dto.setName(operator.getName());
            dto.setType(operator.getType());
            dto.setLoginName(operator.getLoginName());
            dto.setRegionRule(operator.getRegionRule());

            Set<String> groupIdSet = new HashSet<String>();
            List<OperatorGroup> ogList = operatorGroupDao.findByOperatorId(operatorId);
            for (OperatorGroup og : ogList) {
                groupIdSet.add(og.getGroupId());
            }
            dto.setGroupIds(groupIdSet.toArray(new String[0]));
        }
        return dto;
    }

    @Override
    public AuthConfig getAuthConfig(String operatorId) {
        AuthConfig authConfig = new AuthConfig();

        authConfig.setCatalogs(getCatalogMap(operatorId));
        authConfig.setModules(getModuleMap(operatorId));
        authConfig.setOperations(getOperationMap(operatorId));

        return authConfig;
    }

    @Override
    public void modifyGroupPerms(String groupId, String catalogId, GroupPermission... groupPerms) {
        if (Validators.isEmpty(groupId)) {
            return;
        }
        if (Validators.isEmpty(catalogId)) {
            groupPermDao.deleteGroupPerms(groupId);
        }
        else {
            groupPermDao.deleteGroupPerms(groupId, catalogId);
        }
        groupPermDao.insertGroupPerms(groupPerms);
        authCacheService.refreshPermission();
    }

    @Override
    public void freezeOperator(String operatorId) {
        operatorDao.updateOperatorState(operatorId, OperatorStateEnum.UNUSEABLE);
    }

    @Override
    public void unfreezeOperator(String operatorId) {
        operatorDao.updateOperatorState(operatorId, OperatorStateEnum.STATE_ACTIVE);
    }

    @Override
    public void modifyPassword(String operatorId, String password) {
        operatorDao.updateOperatorPassword(operatorId, password);
    }

    @Override
    public void removeAuthCooperator(String operatorId, Integer... cooperatorIds) {
    }

    @Override
    public Set<Integer> getAuthCooperatorIds(String operatorId) {
        Set<Integer> resultSet = new LinkedHashSet<Integer>();
        return resultSet;
    }

    @Override
    public Map<String, AuthGroup> getAllGroupMap() {
        List<AuthGroup> groups = getAllGroups();
        Map<String, AuthGroup> groupMap = new HashMap<String, AuthGroup>(groups.size());
        for (int i = 0; i < groups.size(); i++) {
            AuthGroup group = groups.get(i);
            groupMap.put(group.getId(), group);
        }
        return groupMap;
    }

    private Map<String, AuthCatalog> getCatalogMap(String operatorId) {
        return groupPermDao.findCatalogMap(operatorId);
    }

    private Map<String, AuthModule> getModuleMap(String operatorId) {
        return groupPermDao.findModuleMap(getCatalogMap(operatorId), operatorId);
    }

    private Map<String, AuthOperation> getOperationMap(String operatorId) {
        return groupPermDao.findOperationMap(getModuleMap(operatorId), operatorId);
    }

    private boolean isSystemGroupUser(String operatorId) {
        boolean isSystemGroupUser = false;
        List<OperatorGroup> operatorGroupList = operatorGroupDao.findByOperatorId(operatorId);
        Set<String> groupIdSet = new HashSet<String>();
        for (OperatorGroup og : operatorGroupList) {
            groupIdSet.add(og.getGroupId());
        }
        List<AuthGroup> groupList = authGroupDao.findByIds(groupIdSet.toArray(new String[0]));
        for (AuthGroup group : groupList) {
            if (AuthGroupTypeEnum.SYSTEM.equals(group.getType())) {
                isSystemGroupUser = true;
                break;
            }
        }
        return isSystemGroupUser;
    }

    @Override
    public Map<String, List<AuthGroupUser>> getGroupUsers() {
        return authGroupDao.findGroupUsers();
    }

    public List<AuthGroup> getAllGroups() {
        return authGroupDao.findAll();
    }

    public void setOperatorGroupDao(OperatorGroupDao operatorGroupDao) {
        this.operatorGroupDao = operatorGroupDao;
    }

    public void setOperatorDao(OperatorDao operatorDao) {
        this.operatorDao = operatorDao;
    }

    public void setAuthGroupDao(AuthGroupDao authGroupDao) {
        this.authGroupDao = authGroupDao;
    }

    public void setGroupPermDao(GroupPermDao groupPermDao) {
        this.groupPermDao = groupPermDao;
    }

    @Override
    public void copyAuthCooperator(String srcOperId, boolean clearDesAuth, String... desOperIds) {
        return;
    }

    @Override
    public Map<String, Set<Integer>> getAuthCooperatorIds(String... operatorIds) {
        return Collections.emptyMap();
    }

}
